﻿// LoadStoreInstruction.cs
// Contains a classs for a load store instruction instruction. It is a parent class


using System;


namespace armsim
{
    /// <summary>
    /// Class for an Arm Load Store Instruction
    /// </summary>
    public class LoadStoreInstruction : BaseInstruction
    {
        /// <summary>
        /// Pre/Post Index flag
        /// </summary>
        public uint P { get; protected set; }

        /// <summary>
        /// Offset sign
        /// </summary>
        public uint U { get; protected set; }

        /// <summary>
        /// Byte/Word access
        /// </summary>
        public uint B { get; protected set; }

        /// <summary>
        /// Writeback
        /// </summary>
        public uint W { get; protected set; }

        /// <summary>
        /// Load or Store?
        /// </summary>
        public uint L { get; protected set; }

        /// <summary>
        /// The first Operand register
        /// </summary>
        public uint Rn { get; protected set; }

        /// <summary>
        /// The destination Register
        /// </summary>
        public uint Rd { get; protected set; }

        /// <summary>
        /// The Offset either immediate or immediate shifted register
        /// </summary>
        public LSOffset Offset { get; protected set; }


        /// <summary>
        /// Initializes a new LoadStoreInstruction
        /// </summary>
        /// <param name="instruction">itialized from this</param>
        public LoadStoreInstruction(uint instruction) : base(instruction)
        {
            this.P = VirtualMemory.ExtractBits(instruction, 24, 24);
            this.U = VirtualMemory.ExtractBits(instruction, 23, 23);
            this.B = VirtualMemory.ExtractBits(instruction, 22, 22);
            this.W = VirtualMemory.ExtractBits(instruction, 21, 21);
            this.L = VirtualMemory.ExtractBits(instruction, 20, 20);

            this.Rn = VirtualMemory.ExtractBits(instruction, 16, 19);
            this.Rd = VirtualMemory.ExtractBits(instruction, 12, 15);

            var bit25 = VirtualMemory.ExtractBits(instruction, 25, 25);
            //var bits25To27 = Memory.ExtractBits(instruction, 25, 27);

            //if (bits25To27 == 4u)
            //{
            //    this.Offset = new LSRegisterList(instruction);
            //} 
            switch (bit25)
            {
                case 0u:
                    this.Offset = new LSImmediateOffset(instruction);
                    break;
                case 1u:
                    this.Offset = new LSImmShiftRegOffset(instruction);
                    break;
            }


        }

        /// <summary>
        /// Converts the instruction to assembly code
        /// </summary>
        /// <param name="cpu">grabs info from here</param>
        /// <returns>the assembly code</returns>
        public override string ToAssembly(VirtualCPU cpu)
        {
            var assembly = String.Format("{0}, [{1}", VirtualMemory.RegToAssembly(this.Rd),VirtualMemory.RegToAssembly(this.Rn));

            if (this.P == 0u)
            {
                assembly += "], ";
            }

            assembly += this.Offset.ToAssembly(cpu);

            if (this.P == 1u)
            {
                assembly += "]";
            }

            if (this.P == 1u && this.W == 1u)
            {
                assembly += " !";
            }

            return assembly;
        }
    }
}
